V8算是很新的Javascript引擎,匆忙之間找到的應用不多...目前看到的其實都是在wikipedia上有提到的:
http://en.wikipedia.org/wiki/V8_(JavaScript_engine)
應用協助
http://code.google.com/p/cproxyv8/
http://code.google.com/p/v8-juice/
跟SpiderMonkey比較起來,V8要定義函數跟物件比較麻煩,cproxyv8使用一個proxy類別來包裝自訂的類別,這樣可以讓定義物件的方式比較簡單。
v8-juice也是類似的解決方案,不過他做了更進一步的擴充,包括一組plugin API及做type conversion的API,讓自訂及擴充更方便。
應用
* V8CGI
http://code.google.com/p/v8cgi/
這是一個底層使用V8引擎,整合FastCGI介面的應用,他包涵一個Apache module,透過這個方式,可以讓你用Javascript開發伺服器端的程式。除了使用V8 Javascript引擎,他也整合了一些重要的函式庫:
* I/O: File, Directory, Socket 等原生支援
* DB: MySQL, PostgreSQL, SQLite 等原生支援
* ActiveRecord, Query 等資料庫操作方法
* HTTP, Session, HTML 等協助類別
* Process 行程管理的原生支援
* Assertion, Template 等協助類別
使用V8
V8的主頁:http://code.google.com/p/v8/
V8的簡要開發文件:http://code.google.com/apis/v8/intro.html
V8也提供一個完整的API來使用。V8為了提昇速度,需要用比較麻煩的方式包裝,這樣可以讓他在GC等操作時有更好的效率,以及最終可以做到幾乎將Javascript程式與機器碼直接對應(據說)。
函數的使用比較簡單,他需要使用一個FunctionTemplate來包裝自訂的函數。物件的操作更麻煩,除了需要用ObjectTemplate來包裝,而且手續繁複,對於每個可以操作的屬性,都需要定義Accessor callback來操作,不過他也定義了一些可以進一步管理的函數,例如interceptor函數,可以對這些屬性操作做攔截。也因為使用比較麻煩,所以有像前面介紹的proxy類別這樣用來包裝自訂物件方法,提供統一的操作函數來避免需要大量自訂Accessor函數的狀況。
接下來就從V8的Sample範例中,想辦法拼出一個範例,目的是可以做到:
* 在Global加入一個print函數
* 在Global加入一個printFile函數
* 在Global加入一個自訂物件(結果有問題,以後再來嘗試好了。程式會在正常使用API的時候當掉...也許是版本及編譯器設定的問題...我使用Visual C++ 2008 Express)
然後透過參數傳入要執行的Javascript檔案名稱來執行,這幾個功能模仿之前的Rhino的例子,但是改成用C++搭配V8的API來實作。(全部放到主程式V8_001.cpp中,以程式組織來說這樣做不太好,但是可以運作...)
#include "stdafx.h"
using namespace v8;
Handle<Value> Print(const Arguments& args);
Handle<String> ReadFile(const char* name);
Handle<Value> PrintFile(const Arguments& args);
const char* ToCString(const String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}
Handle<Value> Print(const Arguments& args) {
bool first = true;
for (int i = 0; i < args.Length(); i++) {
HandleScope handle_scope;
if (first) {
first = false;
} else {
printf(" ");
}
String::Utf8Value str(args[i]);
printf("%s", str);
}
printf("\n");
fflush(stdout);
return Undefined();
}
Handle<String> ReadFile(const char* name) {
FILE* file = fopen(name, "rb");
if (file == NULL) return Handle<String>();
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '\0';
for (int i = 0; i < size;) {
int read = fread(&chars[i], 1, size - i, file);
i += read;
}
fclose(file);
Handle<String> result = String::New(chars, size);
delete[] chars;
return result;
}
Handle<Value> PrintFile(const Arguments& args) {
if (args.Length() ==1) {
String::Utf8Value str(args[0]);
Handle<String> result = ReadFile(ToCString(str));
String::AsciiValue rstr(result);
printf("%s", rstr);
}
printf("\n");
fflush(stdout);
return Undefined();
}
int main(int argc, char* argv[])
{
if (argc<2) {
printf("Must provide a javascript file name.");
return 1;
}
const char* str = argv[1];
HandleScope handle_scope;
Handle<ObjectTemplate> global = ObjectTemplate::New();
global->Set(String::New("print"), FunctionTemplate::New(Print));
global->Set(String::New("printFile"), FunctionTemplate::New(PrintFile));
Handle<Context> context = Context::New(NULL, global);
Context::Scope context_scope(context);
Handle<String> file_name = String::New(str);
Handle<String> source = ReadFile(str);
if (source.IsEmpty()) {
printf("Error reading '%s'\n", str);
V8::Dispose();
return 1;
}
Handle<Script> script = Script::Compile(source, file_name);
if (script.IsEmpty()) {
V8::Dispose();
return 1;
} else {
Handle<Value> result = script->Run();
if (result.IsEmpty()) {
V8::Dispose();
return 1;
} else {
if (!result->IsUndefined()) {
String::Utf8Value str(result);
printf("%s\n", str);
}
}
}
V8::Dispose();
return 0;
}
(在stdafx.h裡面有一行:#include <v8.h>,另外要額外加入include及lib目錄指向V8裡面的include目錄及lib產生的目錄。)
測試用的Javascript檔案(test.js):
function pyth(x,y) {
return sqrt(x*x+y*y);
}
function sqrt(x) {
return x*x;
}
print(pyth(2,3)+"\n");
printFile('test.js');
測試結果會跑出:
169
function pyth(x,y) {
return sqrt(x*x+y*y);
}
function sqrt(x) {
return x*x;
}
print(pyth(2,3)+"\n");
printFile('test.js');
結束,可惜目前只試出加入函數的方法...(不過我也試了半天而已就是了,應該早一點開始嘗試,這樣就不用趕截稿時間了。ReadFile、Print等函數其實是從Shell.cc裡面直接copy來用的,我只另外寫一個簡單的PrintFile。目前要print中文似乎有些問題,這也是要再研究的。)